#ifndef __C_SCENE_NODE_ANIMATOR_NEWTON_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_NEWTON_H_INCLUDED__

#include "irrList.h"
#include "ISceneNode.h"
#include "ISceneNodeAnimator.h"
#include <newton.h>

namespace irr
{
namespace scene
{

    //! Body types
    enum E_NEWTON_BODY_TYPE
    {
        ENBT_CUBE,
        ENBT_SPHERE
    };

    //! An animator that animates the scene node according to the Newton Game Dynamics
    /** A short example of how to use it
    \code
    ISceneNode* node = smgr->addCubeSceneNode();
    CSceneNodeAnimatorNewton* anim = new CSceneNodeAnimatorNewton();
    node->addAnimator(anim);
    anim->drop();
    \endcode
    After the animator is added to a scene node, it takes care of updating the newton world, so
    there's no need to add an update call in the main loop. Only one newton body is created per animator, and
    the animator is only expecting one animateNode call per frame, that means that the animator can only be added
    to one scene node. */
    class CSceneNodeAnimatorNewton : public ISceneNodeAnimator
    {
        public:
            //! Constructor
            CSceneNodeAnimatorNewton(E_NEWTON_BODY_TYPE type = ENBT_CUBE,
                                     const core::vector3df& size = core::vector3df(10,10,10), f32 mass = 10);

            //! destructor
            virtual ~CSceneNodeAnimatorNewton();

            //! animates a scene node
            virtual void animateNode(ISceneNode* node, u32 timeMs);

            //! Gets the newton body
            /** \return Returns the newton body */
            NewtonBody* getNewtonBody()
            {
                return Body;
            }

            //! Gets the newton world
            /** \return Returns the newton world. */
            static NewtonWorld* getNewtonWorld()
            {
                return nWorld;
            }

            //! Sets the gravity
            /** \param newGravity: the new gravity to be used */
            static void setGravity(const core::vector3df& newGravity)
            {
                Gravity = newGravity;
            }

            //! Sets the update interval
            /** \param ms: the update inerval in milli seconds */
            static void setUpdateInterval(f32 ms)
            {
                dt = ms;
            }

            //! Adds some force to the body
            /** \param force: the force vector to add */
            void addForce(const core::vector3df& force)
            {
                BodyUserData.Force[0] = force.X;
                BodyUserData.Force[1] = force.Y;
                BodyUserData.Force[2] = force.Z;
            }

            //! Adds some torque to the body
            /** \param torque: the torque vector to add */
            void addTorque(const core::vector3df& torque)
            {
                BodyUserData.Torque[0] = torque.X;
                BodyUserData.Torque[1] = torque.Y;
                BodyUserData.Torque[2] = torque.Z;
            }

        private:

            //the newton force and torque callback
            static void forceAndTorqueCallback(const NewtonBody* body);
            //the newton transform callback
            static void transformCallback(const NewtonBody* body, const f32* matrix);

            //the mass of the newton body
            f32 Mass;
            //the size of the newton collision
            core::vector3df Size;
            //the type of the newton collision (box or sphere)
            E_NEWTON_BODY_TYPE Type;

            //the newton world
            static NewtonWorld* nWorld;
            //the newton body
            NewtonBody* Body;
            //the gravity of the world
            static core::vector3df Gravity;

            //bool used to check if an animateNode call is the first or not
            bool FirstAnimate;

            /* a list of created animators of this type, this is used to keep track
            of who's updating the newton world, when an animator is deleted the job is
            passed on to the next in the list */
            static core::list<CSceneNodeAnimatorNewton*> CreatedAnimators;
            //bool to check if this animator is updating the newton world
            bool IAmUpdating;

            //current time, gets updated on every animateNode call
            static f32 CurrentTime;
            //the time accumulator is making sure that the world is updated right
            static f32 TimeAccumulator;
            //the time step
            static f32 dt;

            //struct to use as user data for the newton body
            struct SBodyUserData
            {
                SBodyUserData()
                {
                    SceneNode = 0;
                    Force[0] = 0; Force[1] = 0; Force[2] = 0;
                    Torque[0] = 0; Torque[1] = 0; Torque[2] = 0;
                }
                ISceneNode* SceneNode;
                f32 Force[3];
                f32 Torque[3];
            } BodyUserData;
    };

}//end namespace scene
}//end namespace irr

#endif



